package top.v5it.japi.plus.extra.web;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileUrlResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.*;

@Slf4j
@Component
class JapiDenyCnf implements InitializingBean {

    private static final String PREFIX = "[";
    private static final String SUFFIX = "]";
    private static final String GLOBAL = "global";
    private static final String FILENAME = "deny.cnf";
    private static final String ENV_KEY = FILENAME;
    private static Map<String, Set<String>> denyMap;

    @Override
    public void afterPropertiesSet() {
        log.info("初始化deny配置");
        Resource resource = new ClassPathResource(FILENAME);
        List<String> lines = null;
        try {
            if (!resource.exists()) {
                final String filepath = System.getProperty(ENV_KEY);
                resource = new FileUrlResource(filepath);
            }
            lines = FileUtil.readLines(resource.getURL(), Charset.defaultCharset());
        } catch (IOException e) {
            log.warn(e.getMessage(), e);
        }
        if (CollUtil.isEmpty(lines)) return;
        Map<String, Set<String>> setMap = new HashMap<>();
        String group = null;
        for (String line : lines) {
            if (StrUtil.isBlank(line)) continue;
            if (StrUtil.startWith(line, '#')) continue;
            line = StrUtil.trim(line);
            if (StrUtil.contains(line, PREFIX)
                    && StrUtil.contains(line, SUFFIX)
                    && setMap.put(group = line, new HashSet<>()) == null) continue;
            if (StrUtil.isEmpty(group)) throw new UnknownFormatConversionException("[" + FILENAME + "]没有分组配置");
            setMap.get(group).add(line);
        }

        denyMap = Optional
                .ofNullable(denyMap)
                .orElse(MapUtil.unmodifiable(setMap));
        log.info("完成deny配置初始化");
    }

    /**
     * 填充key
     *
     * @param key
     * @return
     */
    private String fillKey(String key) {
        return (StrUtil.startWith(key, PREFIX)
                && StrUtil.endWith(key, SUFFIX)) ? key : PREFIX + key + SUFFIX;
    }

    /**
     * 是否存在
     *
     * @param key
     * @param method
     * @return
     */
    boolean exists(String key, String method) {
        final String fillKey = fillKey(key);
        return Optional
                .ofNullable(denyMap)
                .filter(t -> t.containsKey(fillKey))
                .filter(t -> t.get(fillKey).contains(method))
                .isPresent();
    }

    /**
     * 检测全局
     *
     * @param method
     * @return
     */
    boolean exists(String method) {
        return exists(GLOBAL, method);
    }

    /**
     * 当global为true在局部不符合情况下，验证全局
     *
     * @param key
     * @param method
     * @param global
     * @return
     */
    boolean exists(String key, String method, boolean global) {
        return global ? (exists(key, method) || exists(method)) : exists(key, method);
    }
}
